
package common;

import common.packet.Packet;
import common.packet.PacketHandler;
import common.packet.PacketWithCode;
import java.io.IOException;
import java.net.SocketException;
import java.net.SocketTimeoutException;

/**
 *
 * @author xissburg
 */
public class TimeoutHandler implements ReceiveHandleLoop.ErrorHandler, PacketHandler
{
    private boolean isWaitingResponse;
    private ReceiveHandleLoop receiveHandleLoop;
    private int oldTimeout;
    private int timeout;

    public TimeoutHandler(ReceiveHandleLoop receiveHandleLoop) {
        this(receiveHandleLoop, 8000);
    }

    public TimeoutHandler(ReceiveHandleLoop receiveHandleLoop, int timeout)
    {
        isWaitingResponse = false;
        this.receiveHandleLoop = receiveHandleLoop;
        oldTimeout = 0;
        this.timeout = timeout;
    }

    public boolean onSocketTimeoutException(SocketTimeoutException ex)
    {
        //If it is wainting for a response and it times out, return false to
        //finish the RHL and disconnect the client.
        if (isWaitingResponse) {
            timedout();
            return false;
        }

        receiveHandleLoop.addPacketHandler(this);
        isWaitingResponse = true;
        Client client = receiveHandleLoop.getClient();

        try {
            //If it is waiting a pong and it times out, return false to stop the RHL
            oldTimeout = client.getSocketTimeout();
            client.setSocketTimeout(timeout);
            client.write(new PacketWithCode(Packet.Code.ARE_YOU_ALIVE));
        } catch (IOException ex1) {
            ex1.printStackTrace();
            return false;
        }

        return true;
    }

    public void timedout() {}

    public boolean onIOException(IOException ex)
    {
        ex.printStackTrace();
        return false;
    }

    public void handle(Packet packet)
    {
        //Client is alive, then reset everything back
        receiveHandleLoop.removePacketHandler(getPacketCode());
        isWaitingResponse = false;
        Client client = receiveHandleLoop.getClient();

        try {
            client.setSocketTimeout(oldTimeout);
        } catch (SocketException ex) {
            //do nothing, next steps will take care of errors
        }
    }

    public Packet.Code getPacketCode() {
        return Packet.Code.I_AM_ALIVE;
    }

    public static class AreYouAliveHandler implements PacketHandler
    {
        private Client client;

        public AreYouAliveHandler(Client client) {
            this.client = client;
        }

        public void handle(Packet packet)
        {
            try {
                client.write(new PacketWithCode(Packet.Code.I_AM_ALIVE));
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }

        public Packet.Code getPacketCode() {
            return Packet.Code.ARE_YOU_ALIVE;
        }
    }
}
